#pragma once
#include <iostream>
#include <vector>
#include <string>
#include "../mqcommon/Helper.hpp"
#include "../mqcommon/Log.hpp"
#include "../mqcommon/msg.pb.h"
using namespace std;
namespace mq
{
    class Router
    {
    public:
        static bool isLegalRoutingKey(const std::string &routing_key)
        {
            for (auto &ch : routing_key)
            {
                if (!(('a' <= ch && ch <= 'z') ||
                      ('A' <= ch && ch < 'Z') ||
                      ('0' <= ch && ch <= '9') ||
                      (ch == '.') || (ch == '_')))
                    return false;
            }
            return true;
        }
        static bool isLegalBindingKey(const std::string &binding_key)
        {
            for (auto &ch : binding_key)
            {
                if (!(('a' <= ch && ch <= 'z') ||
                      ('A' <= ch && ch < 'Z') ||
                      ('0' <= ch && ch <= '9') ||
                      (ch == '.') || (ch == '_') ||
                      (ch == '#') || (ch == '*')))
                {
                    DLOG("test1");
                    return false;
                }
            }
            vector<string> sub_words;
            StringHelper::splite(binding_key, ".", sub_words);
            for (auto &word : sub_words)
            {
                if (word.size() > 1 &&
                    (word.find("*") != std::string::npos ||
                     word.find("#") != std::string::npos))
                {
                    DLOG("test2");
                    return false;
                }
            }
            for (int i = 1; i < sub_words.size(); i++)
            {
                if (sub_words[i] == "#" && sub_words[i - 1] == "*")
                    return false;
                if (sub_words[i] == "#" && sub_words[i - 1] == "#")
                    return false;
                if (sub_words[i] == "*" && sub_words[i - 1] == "#")
                    return false;
            }
            return true;
        }
        static bool route(ExchangeType type, const string &routing_key, const string &binding_key)
        {
            if (ExchangeType::FANOUT == type)
                return true;
            else if (ExchangeType::DIRECT == type)
                return routing_key == binding_key;
            vector<string> s;
            vector<string> p;
            StringHelper::splite(routing_key, ".", s);
            StringHelper::splite(binding_key, ".", p);
            int m = s.size();
            int n = p.size();
            vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false));
            dp[0][0] = true;
            if (binding_key[0] == '#')
                dp[0][1] = true;
            for (int i = 0; i < m; ++i)
            {
                for (int j = 0; j < n; ++j)
                {
                    if (p[j] == "#")
                        dp[i + 1][j + 1] = dp[i + 1][j] || dp[i][j + 1];
                    else
                        dp[i + 1][j + 1] = (s[i] == p[j] || p[j] == "*") && dp[i][j];
                }
            }
            return dp[m][n];
        }
    };
}
